package com.open.chat.server.service;

import java.util.Arrays;
import java.util.List;
import java.util.Objects;
import java.util.concurrent.locks.ReentrantReadWriteLock.WriteLock;

import org.jim.core.ImChannelContext;
import org.jim.core.ImConst;
import org.jim.core.ImSessionContext;
import org.jim.core.ImStatus;
import org.jim.core.cache.redis.JedisTemplate;
import org.jim.core.cache.redis.RedisCache;
import org.jim.core.cache.redis.RedisCacheManager;
import org.jim.core.config.ImConfig;
import org.jim.core.message.MessageHelper;
import org.jim.core.packets.Command;
import org.jim.core.packets.Group;
import org.jim.core.packets.JoinGroupRespBody;
import org.jim.core.packets.RespBody;
import org.jim.core.packets.User;
import org.jim.core.packets.UserStatusType;
import org.jim.server.JimServerAPI;
import org.jim.server.command.handler.extend.utils.SystemNotify;
import org.jim.server.command.handler.extend.utils.SystemNotify.Operation;
import org.jim.server.config.ImServerConfig;
import org.jim.server.processor.group.GroupCmdProcessor;
import org.jim.server.protocol.AbstractProtocolCmdProcessor;
import org.tio.utils.lock.ObjWithLock;

import com.alibaba.fastjson.JSONObject;
import com.open.chat.server.common.Common;
import com.open.chat.server.common.redis.CommonKey;

import cn.hutool.core.date.DateUtil;

/**
 * 加入群组拓展业务<br/>
 * @author admin
 *
 */
public class GroupServiceProcessor extends AbstractProtocolCmdProcessor implements GroupCmdProcessor{

	
	/***
	 * 实现业务逻辑参照 LoginReqHandler.initGroup
	 */
	@Override
	public JoinGroupRespBody join(Group joinGroup, ImChannelContext imChannelContext) {
		//可能业务操作
		//1.当用户鉴权成功以后，需要执行JoinGroupReqHandler绑定用户所有组到TIO内存上
		//2.判断该组是否存在等业务逻辑，这个方法根据实际情况写还是不写
		return null;
	}
	
	/**
	 *  获取组序列ID
	 * @return
	 */
	private String getGroupSeqId() {
		//JedisTemplate.me()
		WriteLock countLock = new ObjWithLock<Integer>(0).writeLock();
		countLock.lock();
		try {
			//GROUP_ID_CODE_START
			Integer code = JedisTemplate.me().get(Common.GROUP_ID_KEY, Integer.class);
			if(code == null ) {
				code = Common.GROUP_ID_CODE_START;
			}
			//+1操作
			int  incr = Integer.sum(code.intValue(), 1);
			JedisTemplate.me().set(Common.GROUP_ID_KEY, incr);
			return String.valueOf(incr);
		} catch (Exception e) {
			
			e.printStackTrace();
		}finally {
			countLock.unlock();
		}
		
		//JedisTemplate.me().in
		return null;
	}
	
	@Override
	public RespBody addGroup(Group group, ImChannelContext imChannelContext) {
		RespBody respBody = new RespBody(Command.COMMAND_ADD_GROUP_RESP,ImStatus.C2001);
		ImServerConfig imServerConfig = ImConfig.Global.get();
		MessageHelper messageHelper = imServerConfig.getMessageHelper();
		String groupId = getGroupSeqId();
		//新建组
		Group newGroup = 
					Group.newBuilder()
					.groupId(groupId)
					.name(group.getName())
					.avatar(group.getAvatar())
					.content(group.getContent())
					.setCreateTime(DateUtil.current())
					.setLeaderId(imChannelContext.getUserId())
					.build();
		
		//把自己加进去
		User user = messageHelper.getUserByType(imChannelContext.getUserId(), UserStatusType.ALL.getNumber());
		if(user == null) {
			respBody = new RespBody(Command.COMMAND_ADD_GROUP_RESP,ImStatus.C2002).setMsg("用户不存在");
			//return ProtocolManager.Converter.respPacket(respBody, imChannelContext);
			return respBody;
		}
		//绑定群组，绑定以后，会自动把imChannelContext通道的userId拉入到该Group的群里
		//boolean status =  JimServerAPI.bindGroup(imChannelContext, newGroup);
		//一个用户可能有多个通道
		boolean status =  JimServerAPI.bindGroup(imChannelContext, groupId,user.getUserId());
		if(status) {
			//为保险期间，将人拉入到群里
			messageHelper.addGroupUser(user.getUserId(), newGroup.getGroupId());
			//入缓存
			RedisCache groupCache = RedisCacheManager.getCache(GROUP);
			groupCache.put(groupId+CommonKey.SUFFIX+INFO, newGroup);
		}
		
		return respBody.setData(newGroup);
	}

	@Override
	public RespBody unbind(String groupId, ImChannelContext imChannelContext) {
		ImSessionContext imSessionContext = imChannelContext.getSessionContext();
		User clientUser = imSessionContext.getImClientNode().getUser();
		
		ImServerConfig imServerConfig = ImConfig.Global.get();
		MessageHelper messageHelper = imServerConfig.getMessageHelper();
		
		RespBody respBody = new RespBody(Command.COMMAND_REMOVE_GROUP_RESP,ImStatus.C2001);
		
		
		Group g = messageHelper.getGroupUsers(groupId, UserStatusType.ALL.getNumber());
		if(Objects.isNull(g)) {
			return respBody.setCode(ImStatus.C2002.getCode()).setMsg("该群("+groupId+")不存在");
		}
		if(!g.getLeaderId().equals(clientUser.getUserId())) {
			return respBody.setCode(ImStatus.C2002.getCode()).setMsg("您不是群主，无法解散该群");
		}
		//维护缓存关系
		for(User  user : g.getUsers()) {
			JimServerAPI.unbindGroup(user.getUserId(), groupId);
			//unbind方法监听事件可以已经有处理缓存关系的内容了，这个方法写了只是多删了一遍
			messageHelper.removeGroupUser(user.getUserId(), groupId);
			
			//删除群组的离线消息
			RedisCacheManager.getCache(ImConst.PUSH).remove(ImConst.GROUP+CommonKey.SUFFIX+groupId+CommonKey.SUFFIX+user.getUserId());
			JSONObject js = new JSONObject();
			//前端可能用得着
			js.put("groupId", groupId);
			
			//系统展示
			SystemNotify.notifyUser(
					user.getUserId(), user.getNick(), 
					String.format("群(%s)被解散",g.getName()),Operation.oper_no);
			//通知所有人做业务处理
			SystemNotify.notifyUser(
					user.getUserId(), user.getNick(), 
					String.format("群(%s)被解散",g.getName()),Operation.oper_remove_group,js);
			
		}
		//删除群组
		messageHelper.removeGroup(groupId);
		
		//删除群组的所有消息
		RedisCacheManager.getCache(ImConst.STORE).remove(ImConst.GROUP+CommonKey.SUFFIX+groupId);
		
		
		return respBody;
	}
	
	/**
	 * type 1:退出  2：踢出
	 */
	@Override
	public RespBody removeUser(String groupId, String userIds, Integer type,ImChannelContext imChannelContext) {
		ImServerConfig imServerConfig = ImConfig.Global.get();
		MessageHelper messageHelper = imServerConfig.getMessageHelper();
		RespBody respBody = new RespBody(Command.COMMAND_EXIT_GROUP_RESP,ImStatus.C2001);
		
		ImSessionContext imSessionContext = imChannelContext.getSessionContext();
		User clientUser = imSessionContext.getImClientNode().getUser();
		
		Group g = RedisCacheManager.getCache(GROUP).get(groupId+CommonKey.SUFFIX+INFO , Group.class);
		if(Objects.isNull(g)) {
			return respBody.setCode(ImStatus.C2002.getCode()).setMsg("该群("+groupId+")不存在");
		}
		
		
		String[]  ids = new String[] {};
		
		if(type == 2) {
			ids = userIds.split(Common.COMMA);
			List<String> listIds = Arrays.asList(ids);
			
			if(Objects.isNull(userIds)) {
				return respBody.setCode(ImStatus.C2002.getCode()).setMsg("请选择你要踢出的人");
			}
			
			if(!g.getLeaderId().equals(clientUser.getUserId())) {
				return respBody.setCode(ImStatus.C2002.getCode()).setMsg("您不是群主，无法踢人");
			}
			
			if(listIds.contains(g.getLeaderId())) {
				return respBody.setCode(ImStatus.C2002.getCode()).setMsg("您无法踢出自己");
			}
		}
		if(type == 1) {
			if(g.getLeaderId().equals(clientUser.getUserId())) {
				return respBody.setCode(ImStatus.C2002.getCode()).setMsg("您是群主，无法退出");
			}
			//赋值
			ids = new String[] {clientUser.getUserId()};
			
		}
		String exitUserNames = "";
		String exitUserIds = "";
		for(String id : ids) {
			User user = messageHelper.getUserByType(id, UserStatusType.ALL.getNumber());
			if(user != null) {
				List<String> groups = RedisCacheManager.getCache(USER).listGetAll(user.getUserId()+CommonKey.SUFFIX+GROUP);
				//保证删除的人在组内
				if(groups.contains(groupId)) {
					//维护缓存关系
					messageHelper.removeGroupUser(user.getUserId(), groupId);
					
					//如果该用户在线，那么解绑有效，否则无效；保证用户可以在线时，可以交互
					JimServerAPI.unbindGroup(user.getUserId(), groupId);
					
					//删除群组所有用户的离线消息
					RedisCacheManager.getCache(ImConst.PUSH).remove(ImConst.GROUP+CommonKey.SUFFIX+groupId+CommonKey.SUFFIX+user.getUserId());
					
					
					JSONObject js = new JSONObject();
					//前端可能用得着
					js.put("groupId", groupId);
					//发送系统消息
					
					String msg = "";
					
					if(type == 2) {
						msg = String.format("您被%s移除(%s)群", clientUser.getNick(),g.getName());
						
						
					}else if(type == 1) {
						msg =  String.format("您已经退出(%s)群",g.getName());
						
					}
					//业务操作
					SystemNotify.notifyUser(user.getUserId(), user.getNick(), msg,Operation.oper_exit_group,js);
					//系统通知
					SystemNotify.notifyUser(user.getUserId(), user.getNick(), msg,Operation.oper_no);
					
					exitUserNames = exitUserNames + user.getNick() + ",";
					exitUserIds = exitUserIds + user.getUserId() + ",";
					
				}
			}
			
		}
		if(exitUserIds.length() != 0) {
			exitUserNames = exitUserNames.substring(0, exitUserNames.length() - 1);
			
			//需要通知群组；
			JSONObject js = new JSONObject();
			js.put("inUser", exitUserIds);
			SystemNotify.notifyGroup(
						g.getGroupId(), g.getName(), 
						String.format("%s已离开群", exitUserNames),SystemNotify.Operation.oper_exit_group,js);
			
		}
		
		
		return respBody;
	}

	@Override
	public RespBody editGroup(Group group, ImChannelContext imChannelContext) {
		
		RespBody respBody = new RespBody(Command.COMMAND_EDIT_GROUP_RESP,ImStatus.C2001);
		ImServerConfig imServerConfig = ImConfig.Global.get();
		MessageHelper messageHelper = imServerConfig.getMessageHelper();
		Group g = RedisCacheManager.getCache(GROUP).get(group.getGroupId()+CommonKey.SUFFIX+INFO , Group.class);
		//Group g = messageHelper.getGroupUsers(group.getGroupId(), UserStatusType.ALL.getNumber());
		if(Objects.isNull(g)) {
			return respBody.setCode(ImStatus.C2002.getCode()).setMsg("该群("+group.getName()+")不存在");
		}
		//不是群主无法编辑
		if(!imChannelContext.getUserId().equals(g.getLeaderId())) {
			return respBody.setCode(ImStatus.C2002.getCode()).setMsg("您不是群主,无法编辑");
		}
		
		//编辑组
		g.setName(group.getName());
		g.setAvatar(group.getAvatar());
		g.setContent(group.getContent());
		g.setUpdTime(DateUtil.current());
		
		//绑定群组
		//JimServerAPI.bindGroup(imChannelContext, g);
		//更改缓存
		RedisCache groupCache = RedisCacheManager.getCache(GROUP);
		groupCache.put(g.getGroupId()+CommonKey.SUFFIX+INFO, g);
		//通知群
		ImSessionContext imSessionContext = imChannelContext.getSessionContext();
		User clientUser = imSessionContext.getImClientNode().getUser();
		
		JSONObject js = new JSONObject();
		js.put("group", g);
		SystemNotify.notifyGroup(
				g.getGroupId(), g.getName(), 
				String.format("%s将群名称改为:%s", clientUser.getNick(),g.getName()),SystemNotify.Operation.oper_edit_group,js);
		return respBody.setData(g);
	}

	@Override
	public RespBody addUserToGroup(String groupId, String userIds, ImChannelContext imChannelContext) {
		
		ImServerConfig imServerConfig = ImConfig.Global.get();
		MessageHelper messageHelper = imServerConfig.getMessageHelper();
		
		RespBody respBody = new RespBody(Command.COMMAND_ADD_USER_TO_GROUP_RESP,ImStatus.C2001);
		//组信息
		Group g = RedisCacheManager.getCache(GROUP).get(groupId+CommonKey.SUFFIX+INFO , Group.class);
		if(Objects.isNull(g)) {
			return respBody.setCode(ImStatus.C2002.getCode()).setMsg("该群("+groupId+")不存在");
		}
		ImSessionContext imSessionContext = imChannelContext.getSessionContext();
		User clientUser = imSessionContext.getImClientNode().getUser();
		//TODO 邀请的人员，如果不存在，放弃加入，但不报错，优化时提示
		String[]  ids = userIds.split(Common.COMMA);
		String inUserNames = "";
		String inUserIds = "";
		for(String id : ids) {
			User user = messageHelper.getUserByType(id, UserStatusType.ALL.getNumber());
			if(user != null) {
				//respBody = new RespBody(Command.COMMAND_ADD_USER_TO_GROUP_RESP,ImStatus.C2002).setMsg("用户不存在");
				//return ProtocolManager.Converter.respPacket(respBody, imChannelContext);
				//return respBody;
				List<String> groups = RedisCacheManager.getCache(USER).listGetAll(user.getUserId()+CommonKey.SUFFIX+GROUP);
				//保证邀请的人不在群组内
				if(!groups.contains(groupId)) {
					
					//拉人到数据库，维护该人和组的关系
					messageHelper.addGroupUser(user.getUserId(), groupId);
					
					//如果该用户在线，那么绑定有效，否则无效；保证用户可以在线时，可以跟组交互
					JimServerAPI.bindGroup(imChannelContext, groupId,user.getUserId());
					//如果被邀请的人在线，需要通知到该用户(如果在线），该用户重新获取用户信息
					SystemNotify.notifyUser(
							user.getUserId(), user.getNick(), 
							String.format("您被%s邀请进入到(%s)群", clientUser.getNick(),g.getName()));
					
					inUserNames = inUserNames + user.getNick() + ",";
					inUserIds = inUserIds + user.getUserId() + ",";
				}
				
				
			}
			
			
		}
		if(inUserIds.length() != 0) {
			inUserNames = inUserNames.substring(0, inUserNames.length() - 1);
			//需要通知群组，告知该人被群主拉进房间 ；
			JSONObject js = new JSONObject();
			js.put("inUser", inUserIds);
			SystemNotify.notifyGroup( 
						g.getGroupId(), g.getName(), 
						String.format("%s已进入", inUserNames),SystemNotify.Operation.oper_join_group,js);
			
		}
		
		return respBody;
	}

	@Override
	public RespBody getGroup(String groupId, ImChannelContext imChannelContext) {
		ImServerConfig imServerConfig = ImConfig.Global.get();
		MessageHelper messageHelper = imServerConfig.getMessageHelper();
		
		RespBody respBody = new RespBody(Command.COMMAND_INFO_GROUP_RESP,ImStatus.C2001);
		
		Group group = messageHelper.getGroupUsers(groupId, UserStatusType.ALL.getNumber());
		
		if(group == null) {
			return respBody.setCode(ImStatus.C2002.getCode()).setMsg("群组不存在");
		}
		
		return respBody.setData(group);
	}


}
